package cn.turboinfo.dongying.api.provider.common.service.impl.user;

import cn.turboinfo.dongying.api.domain.common.service.user.*;
import cn.turboinfo.dongying.api.entity.common.enumeration.common.EntityObjectType;
import cn.turboinfo.dongying.api.entity.common.enumeration.user.LoginCheckType;
import cn.turboinfo.dongying.api.entity.common.enumeration.user.LoginNameType;
import cn.turboinfo.dongying.api.entity.common.enumeration.user.UserType;
import cn.turboinfo.dongying.api.entity.common.exception.file.FileAttachmentException;
import cn.turboinfo.dongying.api.entity.common.exception.user.UserTypeRelException;
import cn.turboinfo.dongying.api.entity.common.pojo.user.SysUser;
import cn.turboinfo.dongying.api.entity.common.pojo.user.UserCredential;
import cn.turboinfo.dongying.api.entity.common.pojo.user.UserLoginCreator;
import cn.turboinfo.dongying.api.entity.common.pojo.user.UserTypeRel;
import cn.turboinfo.dongying.api.provider.common.repository.database.user.UserTypeRelDAO;
import cn.turboinfo.dongying.api.provider.common.repository.database.user.UserTypeRelPO;
import lombok.RequiredArgsConstructor;
import net.sunshow.toolkit.core.qbean.api.request.QPage;
import net.sunshow.toolkit.core.qbean.api.request.QRequest;
import net.sunshow.toolkit.core.qbean.api.response.QResponse;
import net.sunshow.toolkit.core.qbean.helper.service.impl.AbstractQServiceImpl;
import org.apache.commons.compress.utils.Lists;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.domain.Page;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.Collection;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

@RequiredArgsConstructor
@Service
public class UserTypeRelServiceImpl extends AbstractQServiceImpl<UserTypeRel> implements UserTypeRelService {
    private final UserTypeRelDAO userTypeRelDAO;

    private final SysUserRoleService sysUserRoleService;

    private final UserLoginService userLoginService;

    private final SysUserService sysUserService;

    private final UserCredentialService userCredentialService;

    @Override
    public List<UserTypeRel> findByUserId(Long userId) {
        return convertStreamQBeanToList(userTypeRelDAO.findByUserId(userId).stream());
    }

    /**
     * 创建公司和用户关联
     */
    @Override
    @Transactional
    public UserTypeRel createShopRel(Long userId, Long shopId) throws UserTypeRelException {
        // 验证关联关系是否已存在 已存在就不操作直接返回
        Optional<UserTypeRelPO> optional = userTypeRelDAO.findByUserIdAndUserTypeAndObjectTypeAndObjectId(userId, UserType.Shop, EntityObjectType.SHOP, shopId);
        if (optional.isPresent()) {
            return convertQBean(optional.get());
        }

        // 一个用户只能关联一个公司
        if (!userTypeRelDAO.findByUserIdAndUserType(userId, UserType.Shop).isEmpty()) {
            throw new UserTypeRelException("当前用户已关联过商户");
        }

        UserTypeRelPO po = new UserTypeRelPO();

        po.setUserType(UserType.Shop);
        po.setUserId(userId);
        po.setObjectType(EntityObjectType.SHOP);
        po.setObjectId(shopId);

        // 一个事务内完成角色绑定
        sysUserRoleService.assignByCode(po.getUserId(), po.getUserType().getRoleCode());

        // 添加小程序登录方式
        assignMiniUserLogin(userId);

        return convertQBean(userTypeRelDAO.save(po));
    }

    @Override
    public boolean hasShopRel(Long userId, Long companyId) {
        return userTypeRelDAO.findByUserIdAndUserTypeAndObjectTypeAndObjectId(userId, UserType.Shop, EntityObjectType.SHOP, companyId).isPresent();
    }

    @Override
    public boolean hasConsumerRel(Long userId) {
        return userTypeRelDAO.findByUserIdAndUserTypeAndObjectTypeAndObjectId(userId, UserType.Consumer, EntityObjectType.DEFAULT, 0L).isPresent();
    }

    @Override
    @Transactional
    public UserTypeRel createConsumerRel(Long userId) throws UserTypeRelException {
        // 验证关联关系是否已存在 已存在就不操作直接返回
        Optional<UserTypeRelPO> optional = userTypeRelDAO.findByUserIdAndUserTypeAndObjectTypeAndObjectId(userId, UserType.Consumer, EntityObjectType.DEFAULT, 0L);
        if (optional.isPresent()) {
            return convertQBean(optional.get());
        }

        UserTypeRelPO po = new UserTypeRelPO();

        po.setUserType(UserType.Consumer);
        po.setUserId(userId);
        // 消费者不需要关联对象
        po.setObjectType(EntityObjectType.DEFAULT);
        po.setObjectId(0L);

        // 一个事务内完成角色绑定
        sysUserRoleService.assignByCode(po.getUserId(), po.getUserType().getRoleCode());

        // 添加小程序登录方式
        assignMiniUserLogin(userId);

        return convertQBean(userTypeRelDAO.save(po));
    }


    /**
     * 创建区域关联
     */
    @Override
    @Transactional
    public List<UserTypeRel> createDivisionRel(Long userId, List<Long> divisionIds) throws UserTypeRelException {
        List<UserTypeRelPO> poList = Lists.newArrayList();
        // 验证关联关系是否已存在 已存在就不操作直接返回
        divisionIds.stream().forEach(divisionId -> {
            Optional<UserTypeRelPO> optional = userTypeRelDAO.findByUserIdAndUserTypeAndObjectTypeAndObjectId(userId, UserType.Default, EntityObjectType.DIVISION, divisionId);
            if (optional.isPresent()) {
                poList.add(optional.get());
            } else {
                UserTypeRelPO po = new UserTypeRelPO();
                po.setUserType(UserType.Default);
                po.setUserId(userId);
                po.setObjectType(EntityObjectType.DIVISION);
                po.setObjectId(divisionId);
                poList.add(userTypeRelDAO.save(po));
            }
        });

        return convertStreamQBeanToList(poList.stream());
    }

    @Override
    @Transactional
    public UserTypeRel createCommunityRel(Long userId, Long communityId) throws UserTypeRelException {
        UserTypeRelPO po = new UserTypeRelPO();
        po.setUserType(UserType.Community);
        po.setUserId(userId);
        po.setObjectType(EntityObjectType.COMMUNITY);
        po.setObjectId(communityId);

        // 一个事务内完成角色绑定
        sysUserRoleService.assignByCode(po.getUserId(), po.getUserType().getRoleCode());
        return convertQBean(userTypeRelDAO.save(po));
    }

    /**
     * 获取区域关联
     *
     * @param userTypeRels
     * @return
     */
    @Override
    public List<UserTypeRel> getDivisionRel(List<UserTypeRel> userTypeRels) {
        return userTypeRels.stream().filter(userTypeRel -> userTypeRel.getObjectType().equals(EntityObjectType.DIVISION)).collect(Collectors.toList());
    }


    @Override
    public List<UserTypeRel> findByUserIdAndUserTypeAndObjectType(Long userId, UserType userType, EntityObjectType objectType) {
        return convertStreamQBeanToList(userTypeRelDAO.findByUserIdAndUserTypeAndObjectType(userId, userType, objectType).stream());
    }

    // 添加小程序登录方式
    private void assignMiniUserLogin(Long userId) {
        SysUser sysUser = sysUserService.getByIdEnsure(userId);

        // 如果有设置密码 添加密码登录方式
        Optional<UserCredential> userCredentialOptional = userCredentialService.findUserDefault(userId);
        if (userCredentialOptional.isPresent()) {
            // 小程序端不开放用户名登录
//            if (StringUtils.isNotEmpty(sysUser.getUsername())) {
//                UserLoginCreator creator = UserLoginCreator
//                        .builder()
//                        .withUserId(userId)
//                        .withLoginName(sysUser.getUsername())
//                        .withLoginNameType(LoginNameType.USERNAME)
//                        .withLoginCheckType(LoginCheckType.FRONT_CREDENTIAL)
//                        .withLoginCheckId(userCredentialOptional.get().getId())
//                        .build();
//                userLoginService.saveIfAbsent(creator);
//            }
            if (StringUtils.isNotEmpty(sysUser.getMobile())) {
                UserLoginCreator creator = UserLoginCreator
                        .builder()
                        .withUserId(userId)
                        .withLoginName(sysUser.getMobile())
                        .withLoginNameType(LoginNameType.PHONE_NUM)
                        .withLoginCheckType(LoginCheckType.FRONT_CREDENTIAL)
                        .withLoginCheckId(userCredentialOptional.get().getId())
                        .build();
                userLoginService.saveIfAbsent(creator);
            }
        }

        // 如果有设置手机号 添加验证码登录方式
        if (StringUtils.isNotEmpty(sysUser.getMobile())) {
            UserLoginCreator creator = UserLoginCreator
                    .builder()
                    .withUserId(userId)
                    .withLoginName(sysUser.getMobile())
                    .withLoginNameType(LoginNameType.PHONE_NUM)
                    .withLoginCheckType(LoginCheckType.FRONT_VERIFY_CODE)
                    .withLoginCheckId(0L)
                    .build();
            userLoginService.saveIfAbsent(creator);
        }
    }

    // 添加后台登录方式
    private void assignAdminUserLogin(Long userId) {
        SysUser sysUser = sysUserService.getByIdEnsure(userId);

        // 如果有设置密码 添加密码登录方式
        Optional<UserCredential> userCredentialOptional = userCredentialService.findUserDefault(userId);
        if (userCredentialOptional.isPresent()) {
            {
                UserLoginCreator.Builder userLoginBuilder = UserLoginCreator.builder()
                        .withUserId(sysUser.getId())
                        .withLoginName(sysUser.getUsername())
                        .withLoginNameType(LoginNameType.USERNAME)
                        .withLoginCheckType(LoginCheckType.ADMIN_CREDENTIAL)
                        .withLoginCheckId(userCredentialOptional.get().getId());
                userLoginService.save(userLoginBuilder.build());
            }
            if (StringUtils.isNotEmpty(sysUser.getMobile())) {
                UserLoginCreator creator = UserLoginCreator
                        .builder()
                        .withUserId(userId)
                        .withLoginName(sysUser.getMobile())
                        .withLoginNameType(LoginNameType.PHONE_NUM)
                        .withLoginCheckType(LoginCheckType.ADMIN_CREDENTIAL)
                        .withLoginCheckId(userCredentialOptional.get().getId())
                        .build();
                userLoginService.saveIfAbsent(creator);
            }
        }

        // 如果有设置手机号 添加验证码登录方式
        if (StringUtils.isNotEmpty(sysUser.getMobile())) {
            UserLoginCreator creator = UserLoginCreator
                    .builder()
                    .withUserId(userId)
                    .withLoginName(sysUser.getMobile())
                    .withLoginNameType(LoginNameType.PHONE_NUM)
                    .withLoginCheckType(LoginCheckType.ADMIN_VERIFY_CODE)
                    .withLoginCheckId(0L)
                    .build();
            userLoginService.saveIfAbsent(creator);
        }

    }

    @Override
    public QResponse<UserTypeRel> findAll(QRequest request, QPage requestPage) {
        return convertQResponse(findAllInternal(request, requestPage));
    }

    @Override
    public List<UserTypeRel> findByUserType(UserType userType) {
        return userTypeRelDAO.findByUserType(userType).stream().map(this::convertQBean).collect(Collectors.toList());
    }

    @Override
    public Long countByUserType(UserType userType) {
        return userTypeRelDAO.countByUserType(userType);
    }

    @Override
    public Long countUser(UserType userType, LocalDateTime start, LocalDateTime end) {
        return userTypeRelDAO.countByUserTypeAndCreatedTimeBetween(userType, start, end);
    }


    @Override
    @Transactional
    public void deleteByIdCollection(Collection<Long> idCollection) throws FileAttachmentException {
        idCollection.forEach(id -> {
            UserTypeRelPO userTypeRelPO = getEntityWithNullCheckForUpdate(id, userTypeRelDAO);
            userTypeRelPO.setDeletedTime(System.currentTimeMillis());
        });
    }

    @Override
    public List<UserTypeRel> findUserTypeAndObjectTypeAndObjectId(UserType userType, EntityObjectType objectType, Long objectId) {
        return convertStreamQBeanToList(userTypeRelDAO.findByUserTypeAndObjectTypeAndObjectId(userType, objectType, objectId).stream());
    }

    @Override
    public List<UserTypeRel> findUserTypeAndObjectTypeAndObjectIdInCollection(UserType userType, EntityObjectType objectType, Collection<Long> objectIdCollection) {
        return convertStreamQBeanToList(userTypeRelDAO.findByUserTypeAndObjectTypeAndObjectIdIn(userType, objectType, objectIdCollection).stream());
    }

    private Page<UserTypeRelPO> findAllInternal(QRequest request, QPage requestPage) {
        return userTypeRelDAO.findAll(convertSpecification(request), convertPageable(requestPage));
    }

}
